%{
%}

%code requires {
#include <iostream>
#include <string>
#include <vector>
#include "Ast.h"

extern int yylex();
extern int yyget_lineno();
extern FILE *yyin;
void yyerror(const char *s);
}

%union {
    int num;
    double fnum;
    std::string *str;
    SpecificationNode *specification;
    ListNode<DefinitionNode*> *definition_list;
    DefinitionNode* definition;
    ModuleDclNode *module_dcl;
    ScopedNameNode *scoped_name;
    ConstDclNode *const_dcl;
    ConstTypeNode* const_type;
    ConstExprNode* const_expr;
    OrExprNode *or_expr;
    XorExprNode *xor_expr;
    AndExprNode *and_expr;
    ShiftExprNode *shift_expr;
    AddExprNode *add_expr;
    MultExprNode *mult_expr;
    UnaryExprNode *unary_expr;
    PrimaryExprNode *primary_expr;
    LiteralNode *literal;
    PositiveIntConstNode *int_const;
    TypeDclNode *type_dcl;
    ConstrTypeDclNode *constr_type;
    TypeSpecNode *type_spec;
    SimpleTypeSpecNode *simple_type;
    TemplateTypeSpecNode *template_type_spec;
    BaseTypeNode *base_type;
    SequenceTypeNode *sequence_type;
    StringTypeNode *string_type;
    WideStringTypeNode *wide_string_type;
    FixedPtTypeNode *fixed_pt_type;
    MapTypeNode *map_type;
    StructDclNode *struct_dcl;
    StructDefNode *struct_def;
    TypeDefDclNode * typedef_dcl;
    ListNode<TypeAnnotationNode*> *type_annotation_list;
    TypeAnnotationNode *type_annotation;
    ListNode<MemberNode*> *member_list;
    MemberNode *member;
    ListNode<FixedArraySizeNode*> *array_dims;
    FixedArraySizeNode *fixed_array_size;
    ListNode<MemberAnnotationNode*> *member_annotation_list;
    MemberAnnotationNode *member_annotation;
    StructForwardDclNode *struct_forward_dcl;
    UnionDclNode *union_dcl;
    UnionDefNode *union_def;
    SwitchTypeSpecNode *switch_type_spec;
    ListNode<CaseNode*> *case_list;
    CaseNode *case_node;
    ListNode<CaseLabelNode*> *case_label_list;
    CaseLabelNode *case_label;
    UnionForwardDclNode *union_forward_dcl;
    EnumDclNode *enum_dcl;
    ListNode<EnumeratorNode*> *enumerator_list;
    EnumeratorNode *enumerator;
    IncludeDclNode *include_dcl;
}

%token T_MODULE
%token T_CONST
%token T_TRUE
%token T_FALSE
%token T_BOOLEAN
%token T_CHAR
%token T_WCHAR
%token T_OCTET
%token T_SHORT
%token T_LONG
%token T_FLOAT
%token T_DOUBLE
%token T_UNSIGNED
%token T_INT8
%token T_UINT8
%token T_INT16
%token T_UINT16
%token T_INT32
%token T_UINT32
%token T_INT64
%token T_UINT64
%token T_STRING
%token T_WSTRING
%token T_FIXED
%token T_MAP
%token T_SEQUENCE
%token T_STRUCT
%token T_ENUM
%token T_UNION
%token T_SWITCH
%token T_CASE
%token T_DEFAULT
%token T_TYPEDEF
%token T_NESTED_ANNOTATION
%token T_FINAL_ANNOTATION
%token T_APPENDABLE_ANNOTATION
%token T_MUTABLE_ANNOTATION
%token T_BIT_BOUND_ANNOTATION
%token T_KEY_ANNOTATION
%token T_ID_ANNOTATION
%token T_VALUE_ANNOTATION
%token T_SHARED_ANNOTATION
%token T_OPTION_ANNOTATION
%token T_MUST_UNDERSTAND_ANNOTATION
%token T_SCOPE
%token T_PLUS
%token T_MINUS
%token T_STAR
%token T_SLASH
%token T_PERCENT
%token T_AMP
%token T_PIPE
%token T_CARET
%token T_TILDE
%token T_LSHIFT
%token T_RSHIFT
%token T_EQUAL
%token T_LBRACE
%token T_RBRACE
%token T_LBRACKET
%token T_RBRACKET
%token T_LANGLE
%token T_RANGLE
%token T_LPAREN
%token T_RPAREN
%token T_COLON
%token T_COMMA
%token T_SEMICOLON
%token T_INCLUDE
%token <str> T_FILEPATH
%token <num> T_INTEGER_LITERAL
%token <fnum> T_FLOAT_LITERAL
%token <str> T_STRING_LITERAL
%token <str> T_IDENTIFIER

%type <specification> specification
%type <definition_list> definition_list
%type <definition> definition
%type <module_dcl> module_dcl
%type <scoped_name> scoped_name
%type <const_dcl> const_dcl
%type <const_type> const_type
%type <const_expr> const_expr
%type <or_expr> or_expr
%type <xor_expr> xor_expr
%type <and_expr> and_expr
%type <shift_expr> shift_expr
%type <add_expr> add_expr
%type <mult_expr> mult_expr
%type <unary_expr> unary_expr
%type <primary_expr> primary_expr
%type <literal> literal
%type <int_const> positive_int_const
%type <type_dcl> type_dcl
%type <constr_type> constr_type_dcl
%type <type_spec> type_spec
%type <simple_type> simple_type_spec
%type <base_type> base_type_spec
%type <base_type> floating_pt_type
%type <base_type> integer_type
%type <base_type> signed_int
%type <base_type> signed_short_int
%type <base_type> signed_long_int
%type <base_type> signed_longlong_int
%type <base_type> unsigned_int
%type <base_type> unsigned_short_int
%type <base_type> unsigned_long_int
%type <base_type> unsigned_longlong_int
%type <base_type> char_type
%type <base_type> wide_char_type
%type <base_type> boolean_type
%type <base_type> octet_type
%type <template_type_spec> template_type_spec
%type <sequence_type> sequence_type
%type <string_type> string_type
%type <wide_string_type> wide_string_type
%type <fixed_pt_type> fixed_pt_type
%type <map_type> map_type
%type <struct_dcl> struct_dcl
%type <struct_def> struct_def
%type <struct_forward_dcl> struct_forward_dcl
%type <type_annotation_list> type_annotation_list
%type <type_annotation> type_annotation
%type <member_list> member_list
%type <member> member
%type <array_dims> array_dims
%type <fixed_array_size> fixed_array_size
%type <member_annotation_list> member_annotation_list
%type <member_annotation> member_annotation
%type <union_dcl> union_dcl
%type <union_def> union_def
%type <switch_type_spec> switch_type_spec
%type <case_list> case_list
%type <case_node> case
%type <case_label_list> case_label_list
%type <case_label> case_label
%type <union_forward_dcl> union_forward_dcl
%type <enum_dcl> enum_dcl
%type <enumerator_list> enumerator_list
%type <enumerator> enumerator
%type <typedef_dcl> typedef_dcl
%type <include_dcl> include_dcl

%%

specification: definition_list { $$ = new SpecificationNode(); $$->set_definitions($1); }

definition_list: definition { $$ = new ListNode<DefinitionNode*>(); $$->add($1); }
    | definition_list definition { $1->add($2); $$ = $1; }

definition: module_dcl T_SEMICOLON { $$ = $1; }
    | const_dcl T_SEMICOLON { $$ = $1; }
    | type_dcl T_SEMICOLON { $$ = $1; }
    | include_dcl { $$ = $1; }

include_dcl: T_INCLUDE T_FILEPATH { $$ = new IncludeDclNode($2); }

module_dcl: T_MODULE T_IDENTIFIER T_LBRACE definition_list T_RBRACE { $$ = new ModuleDclNode($2, $4); }

scoped_name: T_IDENTIFIER { $$ = new ScopedNameNode($1); }
    | T_SCOPE T_IDENTIFIER { $$ = new ScopedNameNode($2); }
    | scoped_name T_SCOPE T_IDENTIFIER { $1->add($3); $$ = $1; }

const_dcl: T_CONST const_type T_IDENTIFIER T_EQUAL const_expr { $$ = new ConstDclNode($2, $3, $5); }

const_type: integer_type { $$ = $1; }
    | floating_pt_type { $$ = $1; }
    | char_type { $$ = $1; }
    | wide_char_type { $$ = $1; }
    | boolean_type { $$ = $1; }
    | octet_type { $$ = $1; }
    | string_type { $$ = $1; }
    | wide_string_type { $$ = $1; }
    | scoped_name { $$ = $1; }

const_expr: or_expr { $$ = $1; }

or_expr: xor_expr { $$ = new OrExprNode(nullptr, $1); }
    | or_expr T_PIPE xor_expr { $$ = new OrExprNode($1, $3); }

xor_expr: and_expr { $$ = new XorExprNode(nullptr, $1); }
    | xor_expr T_CARET and_expr { $$ = new XorExprNode($1, $3); }

and_expr: shift_expr { $$ = new AndExprNode(nullptr, $1); }
    | and_expr T_AMP shift_expr { $$ = new AndExprNode($1, $3); }

shift_expr: add_expr { $$ = new ShiftExprNode(nullptr, $1, ShiftExprNode::ShiftOp::NONE); }
    | shift_expr T_RSHIFT add_expr { $$ = new ShiftExprNode($1, $3, ShiftExprNode::ShiftOp::RIGHT); }
    | shift_expr T_LSHIFT add_expr { $$ = new ShiftExprNode($1, $3, ShiftExprNode::ShiftOp::LEFT); }

add_expr: mult_expr { $$ = new AddExprNode(nullptr, $1, AddExprNode::AddOp::NONE); }
    | add_expr T_PLUS mult_expr { $$ = new AddExprNode($1, $3, AddExprNode::AddOp::PLUS); }
    | add_expr T_MINUS mult_expr { $$ = new AddExprNode($1, $3, AddExprNode::AddOp::MINUS); }

mult_expr: unary_expr { $$ = new MultExprNode(nullptr, $1, MultExprNode::MultOp::NONE); }
    | mult_expr T_STAR unary_expr { $$ = new MultExprNode($1, $3, MultExprNode::MultOp::MULT); }
    | mult_expr T_SLASH unary_expr { $$ = new MultExprNode($1, $3, MultExprNode::MultOp::DIV); }
    | mult_expr T_PERCENT unary_expr { $$ = new MultExprNode($1, $3, MultExprNode::MultOp::MOD); }

unary_expr: T_MINUS primary_expr { $$ = new UnaryExprNode(UnaryExprNode::UnaryOp::MINUS, $2); }
    | T_PLUS primary_expr { $$ = new UnaryExprNode(UnaryExprNode::UnaryOp::PLUS, $2); }
    | T_TILDE primary_expr { $$ = new UnaryExprNode(UnaryExprNode::UnaryOp::NOT, $2); }
    | primary_expr { $$ = new UnaryExprNode(UnaryExprNode::UnaryOp::NONE, $1); }

primary_expr: scoped_name { $$ = new PrimaryExprNode($1, nullptr, nullptr); }
    | literal { $$ = new PrimaryExprNode(nullptr, $1, nullptr); }
    | T_LPAREN const_expr T_RPAREN { $$ = new PrimaryExprNode(nullptr, nullptr, $2); }

literal: T_INTEGER_LITERAL { $$ = new LiteralNode($1); }
    | T_FLOAT_LITERAL { $$ = new LiteralNode($1); }
    | T_STRING_LITERAL { $$ = new LiteralNode($1); }
    | T_TRUE { $$ = new LiteralNode(true); }
    | T_FALSE { $$ = new LiteralNode(false); }

positive_int_const: const_expr { $$ = $1; }

type_dcl: constr_type_dcl { $$ = $1; }
    | typedef_dcl { $$ = $1; }

type_spec: simple_type_spec { $$ = $1; }
    | template_type_spec { $$ = $1; }

simple_type_spec: base_type_spec { $$ = $1; }
    | scoped_name { $$ = $1; }

base_type_spec: integer_type { $$ = $1; }
    | floating_pt_type { $$ = $1; }
    | char_type { $$ = $1; }
    | wide_char_type { $$ = $1; }
    | boolean_type { $$ = $1; }
    | octet_type { $$ = $1; }

floating_pt_type: T_FLOAT { $$ = new BaseTypeNode(BaseTypeNode::Type::FLOAT); }
    | T_DOUBLE { $$ = new BaseTypeNode(BaseTypeNode::Type::DOUBLE); }
    | T_LONG T_DOUBLE { $$ = new BaseTypeNode(BaseTypeNode::Type::LONG_DOUBLE); }

integer_type: signed_int { $$ = $1; }
    | unsigned_int { $$ = $1; }

signed_int: signed_short_int { $$ = $1; }
    | signed_long_int { $$ = $1; }
    | signed_longlong_int { $$ = $1; }

signed_short_int: T_SHORT { $$ = new BaseTypeNode(BaseTypeNode::Type::SHORT); }
    | T_INT16 { $$ = new BaseTypeNode(BaseTypeNode::Type::SHORT); }

signed_long_int: T_LONG { $$ = new BaseTypeNode(BaseTypeNode::Type::LONG); }
    | T_INT32 { $$ = new BaseTypeNode(BaseTypeNode::Type::LONG); }

signed_longlong_int: T_LONG T_LONG { $$ = new BaseTypeNode(BaseTypeNode::Type::LONGLONG); }
    | T_INT64 { $$ = new BaseTypeNode(BaseTypeNode::Type::LONGLONG); }

unsigned_int: unsigned_short_int { $$ = $1; }
    | unsigned_long_int { $$ = $1; }
    | unsigned_longlong_int { $$ = $1; }

unsigned_short_int: T_UNSIGNED T_SHORT { $$ = new BaseTypeNode(BaseTypeNode::Type::USHORT); }
    | T_UINT16 { $$ = new BaseTypeNode(BaseTypeNode::Type::USHORT); }

unsigned_long_int: T_UNSIGNED T_LONG { $$ = new BaseTypeNode(BaseTypeNode::Type::ULONG); }
    | T_UINT32 { $$ = new BaseTypeNode(BaseTypeNode::Type::ULONG); }

unsigned_longlong_int: T_UNSIGNED T_LONG T_LONG { $$ = new BaseTypeNode(BaseTypeNode::Type::ULONGLONG); }
    | T_UINT64 { $$ = new BaseTypeNode(BaseTypeNode::Type::ULONGLONG); }

char_type: T_CHAR { $$ = new BaseTypeNode(BaseTypeNode::Type::CHAR); }
    | T_INT8 { $$ = new BaseTypeNode(BaseTypeNode::Type::CHAR); }

wide_char_type: T_WCHAR { $$ = new BaseTypeNode(BaseTypeNode::Type::WCHAR); }

boolean_type: T_BOOLEAN { $$ = new BaseTypeNode(BaseTypeNode::Type::BOOLEAN); }

octet_type: T_OCTET { $$ = new BaseTypeNode(BaseTypeNode::Type::UCHAR); }
    | T_UINT8 { $$ = new BaseTypeNode(BaseTypeNode::Type::UCHAR); }

template_type_spec: sequence_type { $$ = $1; }
    | string_type { $$ = $1; }
    | wide_string_type { $$ = $1; }
    | fixed_pt_type { $$ = $1; }
    | map_type { $$ = $1; }

sequence_type: T_SEQUENCE T_LANGLE type_spec T_COMMA positive_int_const T_RANGLE { $$ = new SequenceTypeNode($3, $5); }
    | T_SEQUENCE T_LANGLE type_spec T_RANGLE { $$ = new SequenceTypeNode($3); }

string_type: T_STRING T_LANGLE positive_int_const T_RANGLE { $$ = new StringTypeNode($3); }
    | T_STRING { $$ = new StringTypeNode(); }

wide_string_type: T_WSTRING T_LANGLE positive_int_const T_RANGLE { $$ = new WideStringTypeNode($3); }
    | T_WSTRING { $$ = new WideStringTypeNode(); }

fixed_pt_type: T_FIXED T_LANGLE positive_int_const T_COMMA positive_int_const T_RANGLE { $$ = new FixedPtTypeNode($3, $5); }

map_type: T_MAP T_LANGLE type_spec T_COMMA type_spec T_COMMA positive_int_const T_RANGLE { $$ = new MapTypeNode($3, $5, $7); }
    | T_MAP T_LANGLE type_spec T_COMMA type_spec T_RANGLE { $$ = new MapTypeNode($3, $5, nullptr); }

constr_type_dcl: struct_dcl { $$ = $1; }
    | union_dcl { $$ = $1; }
    | enum_dcl { $$ = $1; }

struct_dcl: struct_def { $$ = $1; }
    | struct_forward_dcl { $$ = $1; }

struct_def: type_annotation_list T_STRUCT T_IDENTIFIER T_LBRACE member_list T_RBRACE { $$ = new StructDefNode($3, $5, $1, nullptr); }
    | T_STRUCT T_IDENTIFIER T_LBRACE member_list T_RBRACE { $$ = new StructDefNode($2, $4, nullptr, nullptr); }
    | type_annotation_list T_STRUCT T_IDENTIFIER T_COLON scoped_name T_LBRACE member_list T_RBRACE { $$ = new StructDefNode($3, $7, $1, $5); }
    | T_STRUCT T_IDENTIFIER T_COLON scoped_name T_LBRACE member_list T_RBRACE { $$ = new StructDefNode($2, $6, nullptr, $4); }

type_annotation_list: type_annotation { $$ = new ListNode<TypeAnnotationNode*>(); $$->add($1); }
    | type_annotation_list type_annotation { $1->add($2); $$ = $1; }

type_annotation: T_FINAL_ANNOTATION { $$ = new TypeAnnotationNode(TypeAnnotationNode::AnnotationType::FINAL); }
    | T_APPENDABLE_ANNOTATION { $$ = new TypeAnnotationNode(TypeAnnotationNode::AnnotationType::APPENDABLE); }
    | T_MUTABLE_ANNOTATION { $$ = new TypeAnnotationNode(TypeAnnotationNode::AnnotationType::MUTABLE); }
    | T_NESTED_ANNOTATION { $$ = new TypeAnnotationNode(TypeAnnotationNode::AnnotationType::NESTED); }
    | T_BIT_BOUND_ANNOTATION T_LPAREN positive_int_const T_RPAREN { $$ = new TypeAnnotationNode(TypeAnnotationNode::AnnotationType::BIT_BOUND); $$->setValue($3); }

member_list: member { $$ = new ListNode<MemberNode*>(); $$->add($1); }
    | member_list member { $1->add($2); $$ = $1; }

member: member_annotation_list type_spec T_IDENTIFIER array_dims T_SEMICOLON { $$ = new MemberNode($2, $3, $4, $1); }
    | member_annotation_list type_spec T_IDENTIFIER T_SEMICOLON { $$ = new MemberNode($2, $3, nullptr, $1); }
    | type_spec T_IDENTIFIER array_dims T_SEMICOLON { $$ = new MemberNode($1, $2, $3, nullptr); }
    | type_spec T_IDENTIFIER T_SEMICOLON { $$ = new MemberNode($1, $2, nullptr, nullptr); }
    | type_spec T_SEQUENCE T_SEMICOLON { std::string* memberName = new std::string("sequence"); $$ = new MemberNode($1, memberName, nullptr, nullptr); } // add for ros2 stupid Fibonacci.action use 'sequence' as member identifier

array_dims: fixed_array_size { $$ = new ListNode<FixedArraySizeNode*>(); $$->add($1); }
    | array_dims fixed_array_size { $1->add($2); $$ = $1; }

fixed_array_size: T_LBRACKET positive_int_const T_RBRACKET { $$ = new FixedArraySizeNode($2); }

member_annotation_list: member_annotation { $$ = new ListNode<MemberAnnotationNode*>(); $$->add($1); }
    | member_annotation_list member_annotation { $1->add($2); $$ = $1; }

member_annotation: T_ID_ANNOTATION T_LPAREN positive_int_const T_RPAREN { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::ID_ANNOTATION); $$->setValue($3); }
    | T_VALUE_ANNOTATION T_LPAREN positive_int_const T_RPAREN { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::VALUE_ANNOTATION); $$->setValue($3); }
    | T_KEY_ANNOTATION { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::KEY_ANNOTATION); }
    | T_SHARED_ANNOTATION { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::SHARED_ANNOTATION); }
    | T_MUST_UNDERSTAND_ANNOTATION { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::MUST_UNDERSTAND_ANNOTATION); }
    | T_OPTION_ANNOTATION { $$ = new MemberAnnotationNode(MemberAnnotationNode::AnnotationType::OPTION_ANNOTATION); }

struct_forward_dcl: T_STRUCT T_IDENTIFIER { $$ = new StructForwardDclNode($2); }

union_dcl: union_def { $$ = $1; }
    | union_forward_dcl { $$ = $1; }

union_def: type_annotation_list T_UNION T_IDENTIFIER T_SWITCH T_LPAREN switch_type_spec T_RPAREN T_LBRACE case_list T_RBRACE { $$ = new UnionDefNode($3, $6, $9, $1); }
    | T_UNION T_IDENTIFIER T_SWITCH T_LPAREN switch_type_spec T_RPAREN T_LBRACE case_list T_RBRACE { $$ = new UnionDefNode($2, $5, $8, nullptr); }

switch_type_spec: integer_type { $$ = new SwitchTypeSpecNode($1); }
    | char_type { $$ = new SwitchTypeSpecNode($1); }
    | boolean_type { $$ = new SwitchTypeSpecNode($1); }
    | scoped_name { $$ = new SwitchTypeSpecNode($1); }
    | T_KEY_ANNOTATION integer_type { $$ = new SwitchTypeSpecNode($2, true); }
    | T_KEY_ANNOTATION char_type { $$ = new SwitchTypeSpecNode($2, true); }
    | T_KEY_ANNOTATION boolean_type { $$ = new SwitchTypeSpecNode($2, true); }
    | T_KEY_ANNOTATION scoped_name { $$ = new SwitchTypeSpecNode($2, true); }

case_list: case { $$ = new ListNode<CaseNode*>(); $$->add($1); }
    | case_list case { $1->add($2); $$ = $1; }

case: case_label_list member_list { $$ = new CaseNode($1, $2); }

case_label_list: case_label { $$ = new ListNode<CaseLabelNode*>(); $$->add($1); }
    | case_label_list case_label { $1->add($2); $$ = $1; }

case_label: T_CASE const_expr T_COLON { $$ = new CaseLabelNode($2); }
    | T_DEFAULT T_COLON { $$ = new CaseLabelNode(nullptr); }

union_forward_dcl: T_UNION T_IDENTIFIER { $$ = new UnionForwardDclNode($2); }

enum_dcl: type_annotation_list T_ENUM T_IDENTIFIER T_LBRACE enumerator_list T_RBRACE { $$ = new EnumDclNode($3, $5, $1); }
    | T_ENUM T_IDENTIFIER T_LBRACE enumerator_list T_RBRACE { $$ = new EnumDclNode($2, $4, nullptr); }

enumerator_list: enumerator { $$ = new ListNode<EnumeratorNode*>(); $$->add($1); }
    | enumerator_list T_COMMA enumerator { $1->add($3); $$ = $1; }

enumerator: T_IDENTIFIER { $$ = new EnumeratorNode($1, nullptr); }
    | T_VALUE_ANNOTATION T_LPAREN positive_int_const T_RPAREN T_IDENTIFIER { $$ = new EnumeratorNode($5, $3); }

typedef_dcl: T_TYPEDEF type_spec T_IDENTIFIER { $$ = new TypeDefDclNode($3, $2, nullptr); }
    | T_TYPEDEF type_spec T_IDENTIFIER array_dims { $$ = new TypeDefDclNode($3, $2, $4); }

%%

void yyerror(const char *s) {
    std::cerr << "Line: " << yyget_lineno() << " Error: " << s << std::endl;
}
